//
//  NSArray+Safe.m
//  CommonTool
//
//  Created by Name i on 2022/4/13.
//

#import "NSArray+Safe.h"

@implementation NSArray (Safe)

+ (void)exchangeMethod {
        
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        // class method
        [NSObject tnSwizzlingClassMethod: @selector(arrayWithObjects:count:)
                              withMethod: @selector(safe_arrayWithObjects:count:)
                               withClass: [self class]];

        
        // instance method
        Class __NSArray = NSClassFromString(@"NSArray");
        Class __NSArrayI = NSClassFromString(@"__NSArrayI");
        Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI");
        Class __NSArray0 = NSClassFromString(@"__NSArray0");

        
        // 替换的方法
        [NSObject tnSwizzlingInstanceMethod:@selector(objectsAtIndexes:)
                                 withMethod:@selector(safe_objectsAtIndexes:)
                                  withClass:__NSArray];

        // objectAtIndex
        [NSObject tnSwizzlingInstanceMethod: @selector(objectAtIndex:)
                                 withMethod: @selector(safe_objectAtIndex:)
                                  withClass: __NSArrayI];
        
        [NSObject tnSwizzlingInstanceMethod: @selector(objectAtIndex:)
                                 withMethod: @selector(safe_array0ObjectAtIndex:)
                                  withClass: __NSArray0];
        
        [NSObject tnSwizzlingInstanceMethod: @selector(objectAtIndex:)
                                 withMethod: @selector(safe_singleObjectArrayIObjectAtIndex:)
                                  withClass: __NSSingleObjectArrayI];

        // objectAtIndexedSubscript
        [NSObject tnSwizzlingInstanceMethod: @selector(objectAtIndexedSubscript:)
                                 withMethod: @selector(safe_objectAtIndexedSubscript:)
                                  withClass: __NSArrayI];

        // getObjects:range:
        [NSObject tnSwizzlingInstanceMethod: @selector(getObjects:range:)
                                 withMethod: @selector(safe_getObjects:range:)
                                  withClass: __NSArray];
        [NSObject tnSwizzlingInstanceMethod: @selector(getObjects:range:)
                                 withMethod: @selector(safe_singleObjectArrayIGetObjects:range:)
                                  withClass: __NSSingleObjectArrayI];
        [NSObject tnSwizzlingInstanceMethod: @selector(getObjects:range:)
                                 withMethod: @selector(safe_arrayIGetObjects:range:)
                                  withClass: __NSArrayI];

    });
}


+ (instancetype)safe_arrayWithObjects:(id  _Nonnull const [])objects count:(NSUInteger)cnt {
    id instance = nil;
    
    @try {
        instance = [self safe_arrayWithObjects:objects count:cnt];
    }
    @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:@"NNDefender default is to remove nil object and instance a array."];
        
        //以下是对错误数据的处理，把为nil的数据去掉,然后初始化数组
        NSInteger newObjsIndex = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        
        for (int i = 0; i < cnt; i++) {
            if (objects[i] != nil) {
                newObjects[newObjsIndex] = objects[i];
                newObjsIndex++;
            }
        }
        instance = [self safe_arrayWithObjects:newObjects count:newObjsIndex];
    }
    @finally {
        return instance;
    }
}


- (NSArray *)safe_objectsAtIndexes:(NSIndexSet *)indexes {
    NSArray *targetArray = nil;
    @try {
        targetArray = [self safe_objectsAtIndexes:indexes];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:    NNDefenderDefaultReturnNil];
    } @finally {
        return targetArray;
    }
}


- (void)safe_getObjects:(id  _Nonnull __unsafe_unretained [])objects range:(NSRange)range {
    @try {
        [self safe_getObjects:objects range:range];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:    NNDefenderDefaultIgnore];
    } @finally {
        
    }
}

- (void)safe_singleObjectArrayIGetObjects:(id  _Nonnull __unsafe_unretained [])objects range:(NSRange)range {
    @try {
        [self safe_singleObjectArrayIGetObjects:objects range:range];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:    NNDefenderDefaultIgnore];
    } @finally {
        
    }
}

- (void)safe_arrayIGetObjects:(id  _Nonnull __unsafe_unretained [])objects range:(NSRange)range {
    @try {
        [self safe_arrayIGetObjects:objects range:range];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:    NNDefenderDefaultIgnore];
    } @finally {
        
    }
}


- (id)safe_objectAtIndex: (NSUInteger)index {
    id object = nil;
    @try {
        object = [self safe_objectAtIndex:index];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo: NNDefenderDefaultReturnNil];
        object = nil;
    } @finally {
        return object;
    }
}


- (id)safe_singleObjectArrayIObjectAtIndex: (NSUInteger)index {
    id object = nil;
    @try {
        object = [self safe_singleObjectArrayIObjectAtIndex:index];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo: NNDefenderDefaultReturnNil];
    } @finally {
        return object;
    }
}

- (id)safe_array0ObjectAtIndex: (NSUInteger)index {
    id object = nil;
    @try {
        object = [self safe_array0ObjectAtIndex:index];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:    NNDefenderDefaultReturnNil];
    } @finally {
        return object;
    }
}


- (id)safe_objectAtIndexedSubscript: (NSUInteger)index {
    id object = nil;
    @try {
        object = [self safe_objectAtIndex:index];
    } @catch (NSException *exception) {
        [NNDefender crashWithException:exception defaultToDo:    NNDefenderDefaultReturnNil];
    } @finally {
        return object;
    }
}

@end
